package belf.migrate.engine.ddl.trigger.sqlserver;

import belf.migrate.api.model.QualifiersModel;
import belf.migrate.core.jdbc.FunctionModel;
import belf.migrate.core.jdbc.TypeModel;
import belf.migrate.core.util.StringTool;
import belf.migrate.engine.ddl.BaseDDLConvert;
import belf.migrate.plugin.oracle.antlr.PlSqlParser;
import belf.migrate.plugin.sqlserver.antlr.TSqlParser;
import belf.migrate.plugin.sqlserver.antlr.TSqlParserBaseVisitor;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

public class SqlServer2DMTriggerVisitor extends TSqlParserBaseVisitor<String> {
    //以下5个参数为构造参数
    private BaseDDLConvert ddlConvert;
    private QualifiersModel qualifiersModel;
    private String schema;
    private Map<String, FunctionModel> funcMapping;
    private Map<String, TypeModel> typeMapping;

    // 触发器名称
    private String triggerName;
    // 表名或视图名称
    private String tableOrViewName;
    // 触发器时机{ FOR | AFTER | INSTEAD OF }
    private String eventType = "";
    // 触发器动作[ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ]
    private String dmlTriggerOperation = "";
    // SqlServer的触发器定义里，参数申明在BEGIN..END之间，在达梦的函数定义里参数申明需要提到BEGIN之前
    private List<TSqlParser.Declare_statementContext> declares;
    // 触发器定义语句，可以是多条sql_clauses并列的，甚至不带有BEGIN..END
    private List<TSqlParser.Sql_clausesContext> sqlClauses;

    public SqlServer2DMTriggerVisitor(BaseDDLConvert ddlConvert,
                                   QualifiersModel qualifiersModel,
                                String schema,
                                Map<String, FunctionModel> funcMapping,
                                Map<String, TypeModel> typeMapping) {
        this.ddlConvert = ddlConvert;
        this.qualifiersModel = qualifiersModel;
        this.schema = schema;
        this.funcMapping = funcMapping;
        this.typeMapping = typeMapping;

        declares = new ArrayList<>();
        sqlClauses = new ArrayList<>();
    }

    @Override
    public String visitCreate_or_alter_dml_trigger(TSqlParser.Create_or_alter_dml_triggerContext ctx) {
        //找触发器名称
        List<TSqlParser.Id_Context> ids = ctx.simple_name().id_();
        triggerName = ids.get(ids.size() - 1).getText();
        triggerName = StringTool.removeChars(triggerName, "[]");
        triggerName = qualifiersModel.getLeftQuote()
                + schema
                + qualifiersModel.getRightQuote()
                + "."
                + qualifiersModel.getLeftQuote()
                + triggerName
                + qualifiersModel.getRightQuote();

        //找表名或视图名称
        List<TSqlParser.Id_Context> tableIds = ctx.table_name().id_();
        tableOrViewName = tableIds.get(tableIds.size() - 1).getText();
        tableOrViewName = StringTool.removeChars(tableOrViewName, "[]");
        tableOrViewName = qualifiersModel.getLeftQuote()
                + schema
                + qualifiersModel.getRightQuote()
                + "."
                + qualifiersModel.getLeftQuote()
                + tableOrViewName
                + qualifiersModel.getRightQuote();

        //找触发器动作
        List<TSqlParser.Dml_trigger_operationContext> dmlTriggerOperations = ctx.dml_trigger_operation();
        if (dmlTriggerOperations.size() > 0) {
            List<String> dmls = new ArrayList<>();
            dmlTriggerOperations.stream().forEach(new Consumer<TSqlParser.Dml_trigger_operationContext>() {
                @Override
                public void accept(TSqlParser.Dml_trigger_operationContext dmlTriggerOperationContext) {
                    dmls.add(dmlTriggerOperationContext.getText());
                }
            });
            dmlTriggerOperation = String.join(",", dmls);
        }

        // 找触发器时机
        for (int i = 0; i < ctx.getChildCount() - 1; i++) {
            ParseTree child = ctx.getChild(i);
            ParseTree nextChild = ctx.getChild(i + 1);
            if (child instanceof TerminalNode &&
                    nextChild instanceof TSqlParser.Dml_trigger_operationContext) {
                if ("FOR".equalsIgnoreCase(child.getText())) {
                    eventType = "BEFORE";
                } else if ("INSTEAD".equalsIgnoreCase(child.getText())) {
                    eventType = "INSTEAD OF";
                } else {
                    eventType = "AFTER";
                }
            }
        }

        return visitChildren(ctx);
    }

    @Override
    public String visitDeclare_statement(TSqlParser.Declare_statementContext ctx) {
        declares.add(ctx);
        return visitChildren(ctx);
    }

    @Override
    public String visitSql_clauses(TSqlParser.Sql_clausesContext ctx) {
        if (ctx.getParent() instanceof TSqlParser.Create_or_alter_dml_triggerContext) {
            sqlClauses.add(ctx);
        }
        return visitChildren(ctx);
    }

    public String getTriggerName() {
        return triggerName;
    }

    public String getTableOrViewName() {
        return tableOrViewName;
    }

    public List<TSqlParser.Declare_statementContext> getDeclares() {
        return declares;
    }

    public List<TSqlParser.Sql_clausesContext> getSqlClauses() {
        return sqlClauses;
    }
}
